const timesQueue = require('./TimesQueue');
const crypto = require('crypto');
const AgoraAPIRequest = require('./AgoraAPIRequest');
const errors = require('./error');
const ReTryTimesOutError = require('./ReTryTimesOutError')

module.exports = class AgoraAPIQueue {
	constructor({ logger, options }) {
		this.logger = logger;
		this.queue = new timesQueue(this.worker.bind(this), null, 10);
		this.request = new AgoraAPIRequest({ options });
		this.hashcode = {}
	}

	worker({ type, url, options }, cb) {
		this.request[type](url, options).then(res => cb(null, res)).catch(cb);
	}


	_getHash(args) {
		return crypto.createHash('md5').update(JSON.stringify(args)).digest('hex')
	}


	_rePush(args, resolve, reject, lastError) {
		let hcode = this._getHash(args)
		if (!this.hashcode[hcode]) {
			this.hashcode[hcode] = { times: [1000, 3000, 6000, 10000, 30000] }
		}
		let timeout = this.hashcode[hcode].times.shift()
		if (!timeout) {
			delete this.hashcode[hcode]
			return reject(new ReTryTimesOutError(this.constructor.name, args, lastError));
		}
		this.logger.info(`重新请求数据:${this.constructor.name},timeout:${timeout}`)
		// this.logger.info(JSON.stringify(args))
		this.logger.error(lastError)
		setTimeout(() => this.push(args).then(ret => {
			delete this.hashcode[hcode]
			resolve(ret)
		}).catch(reject), timeout)
	}

	push(args) {
		return new Promise((resolve, reject) => {
			this.queue.push(args, (err, res) => {
				if (err) {
					// 这个可能是系统的错误，重新提交操作
					if (err.type === 'system' && err.code === 'EAI_AGAIN') {
						return this._rePush(args, resolve, reject, err)
					}
					this.logger.error(`agora API 请求出错!`);
					return reject(err);
				}
				// 返回正常状态
				if (res.status === 200) {
					return res.json().then(ret => {
						if (!ret.code) {
							return resolve(ret)
						}
						let error = errors['Error' + ret.code];
						if (error) {
							throw new error(ret);
						}
						throw new errors.CodeError(ret);
					}).catch(err => {
						if (err.reTry) {
							this._rePush(args, resolve, reject, err)
						} else {
							reject(err)
						}
					})
				}
				// 其它的状态错误
				return res.json()
					.catch(e => {
						return { message: 'response返回的json格式获取失败' };
					})
					.then(ret => {
						switch (res.status) {
							case 201:
								// this.logger.error(`agora 录制已经在进行中 ，请勿用同一个 resource ID 重复 start 请求。 status:${res.status}`);
								throw new errors.Error201(ret, res.status);
							case 206:
								// this.logger.error(`agora 整个录制过程中没有用户发流，或部分录制文件没有上传到第三方云存储。 status:${res.status}`);
								throw new errors.Error206(ret, res.status);
							case 400:
							case 401:
								// this.logger.error(`agora 请求参数错误! status:${res.status}`);
								throw new errors.Error400(ret, res.status);
							case 404:
								// this.logger.error(`agora 请求参数错误! status:${res.status}`);
								throw new errors.Error404(ret, res.status);
							case 500:
							case 501:
								// this.logger.error(`agora 服务器内容错误! status:${res.status}`);
								throw new errors.Error500(ret, res.status);
							default:
								// this.logger.error(`agora 未知其它错误! `);
								throw new errors.StatusError(ret, res.status);
						}
					}).catch(err => {
						if (err.reTry) {
							this._rePush(args, resolve, reject, err)
						} else {
							reject(err)
						}
					});
			})
		})

	}

};
